package com.heu.blood.match.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.heu.blood.common.utils.GenerateNumberBySnowFlake;
import com.heu.blood.common.utils.PageUtils;
import com.heu.blood.common.utils.Query;
import com.heu.blood.match.dao.BloodMatchDao;
import com.heu.blood.match.dao.BloodVerifyPatientDao;
import com.heu.blood.match.entity.BloodMatchEntity;
import com.heu.blood.match.entity.BloodVerifyPatientEntity;
import com.heu.blood.match.entity.PatientInformationEntity;
import com.heu.blood.match.service.BloodVerifyPatientService;
import com.heu.blood.match.service.PatientInformationService;
import com.heu.blood.transfusion.entity.TransfusionApplicationEntity;
import com.heu.blood.transfusion.service.TransfusionApplicationService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.logging.log4j.util.Strings;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

import static com.heu.blood.common.enums.CommonEnum.IF_SHOW;
import static com.heu.blood.common.enums.PatientVerifyEnum.*;


@Slf4j
@Service("bloodVerifyPatientService")
public class BloodVerifyPatientServiceImpl extends ServiceImpl<BloodVerifyPatientDao, BloodVerifyPatientEntity> implements BloodVerifyPatientService {

    @Autowired
    BloodVerifyPatientDao bloodVerifyPatientDao;

    @Autowired
    PatientInformationService patientInformationService;

    @Autowired
    TransfusionApplicationService transfusionApplicationService;

    @Autowired
    BloodMatchDao bloodMatchDao;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        // 构造BloodVerifyPatientEntity对象
        BloodVerifyPatientEntity bloodVerifyPatient = new BloodVerifyPatientEntity();
        if (Strings.isNotBlank((String) params.get("patientId"))){
            bloodVerifyPatient.setPatientId((String) params.get("patientId")); // 设置患者id
        }
        if (Strings.isNotBlank((String) params.get("transfusionId"))){
            bloodVerifyPatient.setTransfusionId((String) params.get("transfusionId")); // 设置患者id
        }
        if (Strings.isNotBlank((String) params.get("bloodType"))){
            bloodVerifyPatient.setBloodType((String) params.get("bloodType")); // 设置患者血样
        }
        if (Strings.isNotBlank((String) params.get("aboBloodType"))){
            bloodVerifyPatient.setAboBloodType((String) params.get("aboBloodType")); // 设置患者abo血型
        }
        if (Strings.isNotBlank((String) params.get("rhBloodType"))){
            bloodVerifyPatient.setRhBloodType((String) params.get("rhBloodType")); // 设置患者rh血型
        }
        if (Strings.isNotBlank((String) params.get("verifyResult"))){
            bloodVerifyPatient.setVerifyResult((String) params.get("verifyResult")); // 设置核验结果
        }


        // 构造条件构造器对象
        LambdaQueryWrapper<BloodVerifyPatientEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Strings.isNotBlank(bloodVerifyPatient.getPatientId()), BloodVerifyPatientEntity::getPatientId, bloodVerifyPatient.getPatientId())
                    .eq(Strings.isNotBlank(bloodVerifyPatient.getBloodType()), BloodVerifyPatientEntity::getBloodType, bloodVerifyPatient.getBloodType())
                    .eq(Strings.isNotBlank(bloodVerifyPatient.getAboBloodType()), BloodVerifyPatientEntity::getAboBloodType, bloodVerifyPatient.getAboBloodType())
                    .eq(Strings.isNotBlank(bloodVerifyPatient.getRhBloodType()), BloodVerifyPatientEntity::getRhBloodType, bloodVerifyPatient.getRhBloodType())
                    .eq(Strings.isNotBlank(bloodVerifyPatient.getVerifyResult()), BloodVerifyPatientEntity::getVerifyResult, bloodVerifyPatient.getVerifyResult())
                    .eq(Strings.isNotBlank(bloodVerifyPatient.getTransfusionId()), BloodVerifyPatientEntity::getTransfusionId, bloodVerifyPatient.getTransfusionId())
                    .eq(BloodVerifyPatientEntity::getIfShow, IF_SHOW.code());

        IPage<BloodVerifyPatientEntity> page = this.page(
                new Query<BloodVerifyPatientEntity>().getPage(params),
                queryWrapper
        );

        return new PageUtils(page);
    }

    /**
     * 通过输血申请单信息来新增对应的病人核验信息
     * @param transfusionApplications
     * @return
     */
    @Override
    public Boolean saveWithTransfusion(List<TransfusionApplicationEntity> transfusionApplications) {

        // 1、先获取bloodVerifyPatient中所有的transfusionId
        List<String> existTransfuisonId = this.list().stream().map(BloodVerifyPatientEntity::getTransfusionId).collect(Collectors.toList());
        // 1、创建List<BloodVerifyPatientEntity>对象用于存储需要插入的数据
        List<BloodVerifyPatientEntity> bloodVerifyPatientEntities = new ArrayList<>();

        // 2、获取transfusionApplications中的所有transfusionId
        List<String> transfusionIds = transfusionApplications.stream().map(TransfusionApplicationEntity::getTransfusionId).collect(Collectors.toList());
        // 3、过滤出未在bloodVerify表中出现的transfusionId
        List<String> newTransfusionIds = transfusionIds.stream().filter(transfusionId->!existTransfuisonId.contains(transfusionId)).collect(Collectors.toList());
        if (newTransfusionIds == null){
            return false;
        }

        // 4、查询所有输血申请单号对应的实体对象
        Map<String, TransfusionApplicationEntity> transfusionApplicationMap = new HashMap<>();
        for (String transfusionId : newTransfusionIds) {
            TransfusionApplicationEntity transfusionApplication = transfusionApplicationService.queryByTransfusionId(transfusionId);
            if (transfusionApplication != null) {
                transfusionApplicationMap.put(transfusionId, transfusionApplication);
            }
        }
        // 5、用缓存的实体对象创建BloodVerifyPatientEntity
        for (String transfusionId : transfusionApplicationMap.keySet()) {
            TransfusionApplicationEntity transfusionApplication = transfusionApplicationMap.get(transfusionId);
            BloodVerifyPatientEntity bloodVerifyPatient = new BloodVerifyPatientEntity();
            bloodVerifyPatient.setTransfusionId(transfusionApplication.getTransfusionId());
            bloodVerifyPatient.setPatientId(transfusionApplication.getPatientId());
            bloodVerifyPatient.setBloodType(transfusionApplication.getBloodType());
            bloodVerifyPatient.setAboBloodType(transfusionApplication.getAboBloodType());
            bloodVerifyPatient.setRhBloodType(transfusionApplication.getRhBloodType());
            bloodVerifyPatient.setCollectTime(transfusionApplication.getCollectTime());
            bloodVerifyPatientEntities.add(bloodVerifyPatient);
        }
        // 5、保存新增结果
        boolean result =  this.saveBatch(bloodVerifyPatientEntities);
        return result;
    }

    /**
     * 通过比对患者信息表和患者核查表
     * @param bloodVerifyPatient
     */
    @Override
    public Pair<Boolean, String> verify(BloodVerifyPatientEntity bloodVerifyPatient) {
        PatientInformationEntity patientInformation = patientInformationService.queryWithPatientId(bloodVerifyPatient.getPatientId());
        // 1、提取出患者核查表中的输血申请单id, 患者id和对应的abo，rh结果(通过输血申请单id和患者id来唯一确定一条病人核查记录)
        String aboBloodType = bloodVerifyPatient.getAboBloodType();
        String rhBloodType = bloodVerifyPatient.getRhBloodType();
        // 2、提取出患者信息表中的血液信息
        String aboBloodTypeVerify = patientInformation.getAboBloodType();
        String rhBloodTypeVerify = patientInformation.getRhBloodType();
        // 3、比对血型，并设置verify_result
        String verifyResult;
        boolean reasonOption = true; // 通过这个值确定不通过原因,0表示通过，1表示abo复查不符，2表示rh复查不符，3表示abo和rh都不符
        if (Objects.equals(aboBloodTypeVerify, aboBloodType)) {
            if (Objects.equals(rhBloodTypeVerify, rhBloodType)) {
                verifyResult = VERIFY_PASS.code();
                // 核验通过可以保存结果到交叉配血表
                // 先通过transfusionId找到输血申请单信息
                TransfusionApplicationEntity transfusionApplicationEntity = transfusionApplicationService.queryByTransfusionId(bloodVerifyPatient.getTransfusionId());
                if (transfusionApplicationEntity == null){
                    // 代表没有找到这个输血申请单号
                    log.info(bloodVerifyPatient.getTransfusionId() + "不存在");
                } else {
                    BloodMatchEntity bloodMatchEntity = new BloodMatchEntity();
                    // 使用雪花算法生成matchId
                    GenerateNumberBySnowFlake generateNumberBySnowFlake = new GenerateNumberBySnowFlake(transfusionApplicationEntity.getTransfusionId(), "MATCH");
                    bloodMatchEntity.setMatchId(generateNumberBySnowFlake.genNumberByflag());
                    // 设置其他属性值
                    bloodMatchEntity.setApplicationId(transfusionApplicationEntity.getTransfusionId());
                    bloodMatchEntity.setPatientId(transfusionApplicationEntity.getPatientId());
                    bloodMatchEntity.setAboTypePatient(transfusionApplicationEntity.getAboBloodType());
                    bloodMatchEntity.setRhTypePatient(transfusionApplicationEntity.getRhBloodType());
                    bloodMatchEntity.setBloodTypePatient(transfusionApplicationEntity.getBloodType());
                    bloodMatchDao.insert(bloodMatchEntity); // 插入一条新的交叉配血记录
                }
            } else {
                verifyResult = VERIFY_RH_FAIL.code();
                reasonOption = false;
            }
        } else {
            if (Objects.equals(rhBloodTypeVerify, rhBloodType)) {
                verifyResult = VERIFY_ABO_FAIL.code();
                reasonOption = false;
            } else {
                verifyResult = VERIFY_ABO_RH_FAIL.code();
                reasonOption = false;
            }
        }
        // 4、设置verify_result给patientInformationEntity
        bloodVerifyPatient.setVerifyResult(verifyResult);
        // 5、保存bloodVerifyPatient到患者核查表
        this.updateById(bloodVerifyPatient);
        // 6、返回结果
        return Pair.of(reasonOption, verifyResult);
    }

    /**
     * 条件查询患者核验表信息
     * @param bloodVerifyPatientEntity
     * @return
     */
    @Override
    public List<BloodVerifyPatientEntity> query(BloodVerifyPatientEntity bloodVerifyPatientEntity) {
        // 构造条件构造器
        LambdaQueryWrapper<BloodVerifyPatientEntity> queryWrapper = new LambdaQueryWrapper<>();
        // 添加过滤条件
        queryWrapper.eq(Strings.isNotBlank(bloodVerifyPatientEntity.getPatientId()), BloodVerifyPatientEntity::getPatientId, bloodVerifyPatientEntity.getPatientId())
                .eq(Strings.isNotBlank(bloodVerifyPatientEntity.getTransfusionId()), BloodVerifyPatientEntity::getTransfusionId, bloodVerifyPatientEntity.getTransfusionId())
                .eq(Strings.isNotBlank(bloodVerifyPatientEntity.getBloodType()), BloodVerifyPatientEntity::getBloodType, bloodVerifyPatientEntity.getBloodType())
                .eq(Strings.isNotBlank(bloodVerifyPatientEntity.getAboBloodType()), BloodVerifyPatientEntity::getAboBloodType, bloodVerifyPatientEntity.getAboBloodType())
                .eq(Strings.isNotBlank(bloodVerifyPatientEntity.getRhBloodType()), BloodVerifyPatientEntity::getRhBloodType, bloodVerifyPatientEntity.getRhBloodType())
                .eq(Strings.isNotBlank(bloodVerifyPatientEntity.getVerifyResult()), BloodVerifyPatientEntity::getVerifyResult, bloodVerifyPatientEntity.getVerifyResult())
                .eq(BloodVerifyPatientEntity::getIfShow, IF_SHOW.code());
        return bloodVerifyPatientDao.selectList(queryWrapper);
    }
}